package net.blank.ui
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.InteractiveObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.StyleSheet;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.utils.getTimer;
	
	import net.blank.pool.Pool;
	import net.blank.timerUtl.PublicTimer;
	import net.blank.ui.core.InteractiveUI;
	
	/**
	 * 提示
	 * @author blank
	 * 
	 */
	final public class Tip
	{
		/**
		 * 计时器(执行间隔500ms)
		 */
		private static const TIMER_500MS:PublicTimer=new PublicTimer(500);
		
		/**
		 * tip显示对象的显示偏移<br/>
		 * <b>注意:</b><br/>
		 * 1.在 show 方法中指定显示位置时,此设置将被忽略<br/>
		 * 2.tip内容对象在 x 坐标上超过其父对象的 width 时,此值的 x 值将被忽略<br/>
		 * 3.tip内容对象在 y 坐标上超过其父对象的 height 时,此值的 y 值将被忽略
		 */
		public static var offset:Point=new Point(2,16);
		
		/**
		 * tip目标对象列表,一个目标对象只能有一个tip
		 */
		private static var targets:Vector.<InteractiveObject>=new Vector.<InteractiveObject>();
		
		/**
		 * tip显示对象
		 */
		private var $tipContent:DisplayObject;
		
		/**
		 * tip对象的目标
		 */
		private var $target:InteractiveObject;
		
		/**
		 * 显示的毫秒数
		 */
		private var $showMillisecond:int;
		
		/**
		 * 延迟显示的毫秒数
		 */
		private var $showDelayMillisecond:int;
		
		/**
		 * 延迟消失的毫秒数
		 */
		private var $hideDelayMillisecond:int;
		
		/**
		 * 显示的位置
		 */
		private var $showLoc:Point;
		
		/**
		 * tip显示对象的父对象
		 */
		private var $parent:DisplayObjectContainer;
		
		/**
		 * 上一次获取的系统时间
		 */
		private var lastTime:int;
		/**
		 * 当前的系统时间
		 */
		private var curTime:int;
		
		/**
		 * 计算tip显示对象的位置
		 * 
		 */
		private function countTipContentLoc():void{
			if($showLoc){
				$tipContent.x=$showLoc.x;
				$tipContent.y=$showLoc.y;
			}else{
				if($parent.mouseX + $tipContent.width < $parent.width){
					$tipContent.x=$parent.mouseX + (offset ? offset.x : 0);
				}else{
					var tempX:int=$parent.width - $tipContent.width;
					if(tempX > 0){
						$tipContent.x=tempX;
					}else{
						$tipContent.x=0;
					}
				}
				if($parent.mouseY + $tipContent.height < $parent.height){
					$tipContent.y=$parent.mouseY + (offset ? offset.y : 0);;
				}else{
					var tempY:int=$parent.mouseY - $tipContent.height;
					if(tempY > 0){
						$tipContent.y=tempY;
					}else{
						$tipContent.y=0;
					}
				}
			}
		}
		
		/**
		 * 摧毁
		 * 
		 */
		private function destroy():void{
			var index:int=targets.indexOf($target);
			if(index != -1){
				targets.splice(index,1);
			}
			
			$target=null;
			$tipContent=null;
			
			Pool.storeObj(this);
		}
		
		/**
		 * tip显示对象从其父对象移除
		 * @param evt
		 * 
		 */
		private function removedHandler(evt:Event):void{
			TIMER_500MS.removeFunc(countShowDelay);
			TIMER_500MS.removeFunc(countShow);
			TIMER_500MS.removeFunc(countHide);
			
			$tipContent.removeEventListener(Event.REMOVED,removedHandler);
			if($tipContent is InteractiveObject){
				$tipContent.removeEventListener(MouseEvent.ROLL_OVER,rollOverHandler);
				$tipContent.removeEventListener(MouseEvent.ROLL_OUT,rollOutHandler);
			}
			$target.removeEventListener(MouseEvent.ROLL_OUT,rollOutHandler);
			
			destroy();
		}
		
		/**
		 * 附着的宿主对象被从显示列表移除
		 * @param evt
		 * 
		 */
		private function removeFromStageForTarget(evt:Event):void{
			hide();
		}
		
		/**
		 * 鼠标进入tip显示对象或tip对象的目标
		 * @param evt
		 * 
		 */
		private function rollOverHandler(evt:MouseEvent):void{
			TIMER_500MS.removeFunc(countHide);
			TIMER_500MS.addFunc(countShow);
		}
		
		/**
		 * 鼠标移出tip显示对象或tip对象的目标
		 * @param evt
		 * 
		 */
		private function rollOutHandler(evt:MouseEvent):void{
			TIMER_500MS.removeFunc(countShow);
			startHideDelay();
		}
		
		/**
		 * 鼠标在显示延迟阶段移出tip显示对象或tip对象的目标
		 * @param evt
		 * 
		 */
		private function rollOutForShowDelayingHandler(evt:MouseEvent):void{
			TIMER_500MS.removeFunc(countShowDelay);
			
			$target.removeEventListener(MouseEvent.ROLL_OUT,rollOutForShowDelayingHandler);
			
			destroy();
		}
		
		/**
		 * tip显示对象被点击
		 * @param evt
		 * 
		 */
		private function clickHandler(evt:MouseEvent):void{
			if($showMillisecond > 0){
				TIMER_500MS.removeFunc(countShow);
			}
		}
		
		/**
		 * 隐藏
		 * 
		 */
		private function hide():void{
			if($tipContent.parent){
				$tipContent.parent.removeChild($tipContent);
			}
		}
		
		/**
		 * 计算隐藏延迟
		 * 
		 */
		private function countHide():void{
			if(getTimer()-lastTime >= $hideDelayMillisecond){
				hide();
				TIMER_500MS.removeFunc(countHide);
			}
		}
		
		/**
		 * 开始隐藏延迟
		 * 
		 */
		private function startHideDelay():void{
			lastTime=getTimer();
			TIMER_500MS.addFunc(countHide);
		}
		
		/**
		 * 计算显示时长
		 * 
		 */
		private function countShow():void{
			curTime=getTimer();
			$showMillisecond -= curTime - lastTime;
			lastTime=curTime;
			if($showMillisecond <= 0){
				startHideDelay();
				TIMER_500MS.removeFunc(countShow);
			}
		}
		
		/**
		 * 开始显示
		 * 
		 */
		private function startShow():void{
			countTipContentLoc();
			
			$tipContent.addEventListener(Event.REMOVED,removedHandler);
			if($tipContent is InteractiveObject){
				$tipContent.addEventListener(MouseEvent.ROLL_OVER,rollOverHandler);
				$tipContent.addEventListener(MouseEvent.ROLL_OUT,rollOutHandler);
				$tipContent.addEventListener(MouseEvent.CLICK,clickHandler);
			}
			$target.addEventListener(Event.REMOVED_FROM_STAGE,removeFromStageForTarget);
			if($target is InteractiveUI){
				InteractiveUI($target).addEventListenerIgnoreEnabledState(MouseEvent.ROLL_OUT,rollOutHandler);
			}else{
				$target.addEventListener(MouseEvent.ROLL_OUT,rollOutHandler);
			}
			
			$parent.addChild($tipContent);
			
			lastTime=getTimer();
			TIMER_500MS.addFunc(countShow);
		}
		
		/**
		 * 计算显示延迟
		 * 
		 */
		private function countShowDelay():void{
			curTime=getTimer();
			$showDelayMillisecond -= curTime - lastTime;
			lastTime=curTime;
			if($showDelayMillisecond <= 0){
				startShow();
				TIMER_500MS.removeFunc(countShowDelay);
				$target.removeEventListener(MouseEvent.ROLL_OUT,rollOutForShowDelayingHandler);
			}
		}
		
		/**
		 * 开始显示延迟
		 * 
		 */
		private function startShowDelay():void{
			$target.addEventListener(Event.REMOVED_FROM_STAGE,removeFromStageForTarget);
			if($target is InteractiveUI){
				InteractiveUI($target).addEventListenerIgnoreEnabledState(MouseEvent.ROLL_OUT,rollOutForShowDelayingHandler);
			}else{
				$target.addEventListener(MouseEvent.ROLL_OUT,rollOutForShowDelayingHandler);
			}
			
			lastTime=getTimer();
			TIMER_500MS.addFunc(countShowDelay);
		}
		
		/**
		 * 显示tip对象
		 * @param tipContent 要显示的tip内容对象
		 * @param target tip的附着对象
		 * @param showMillisecond 显示时长(毫秒)
		 * @param showDelayMillisecond 显示延迟(毫秒)
		 * @param hideDelayMillisecond 隐藏延迟(毫秒)
		 * @param showLoc 显示位置,如果不指定此值,则 tipContent 根据鼠标的位置进行显示.指定此值时,静态变量 offset 将被忽略
		 * @param parent tipContent显示的父对象,一般指定为 stage 
		 * 
		 */
		public static function show(
			tipContent:DisplayObject,
			target:InteractiveObject,
			showMillisecond:int=3500,
			showDelayMillisecond:int=400,
			hideDelayMillisecond:int=200,
			showLoc:Point=null,
			parent:DisplayObjectContainer=null
		):void{
			if(targets.indexOf(target) == -1){
				targets[targets.length]=target;
				
				var tip:Tip=Pool.restoreObj(Tip);
				if(!tip){
					tip=new Tip();
				}
				
				tip.$tipContent=tipContent;
				tip.$target=target;
				tip.$showMillisecond=showMillisecond;
				tip.$showDelayMillisecond=showDelayMillisecond;
				tip.$hideDelayMillisecond=hideDelayMillisecond;
				tip.$showLoc=showLoc;
				tip.$parent=parent ? parent : SystemManager.getInstance().application;
				
				tip.startShowDelay();
			}
		}
		
		/**
		 * tip文本显示对象
		 */
		private static var txfTip:TextField=new TextField();
		
		/**
		 * 如果 tip 属性是文本,此常量为 tip 的显示内容的默认背景属性
		 */
		private static const DEFAULT_BACKGROUND:Boolean=true;
		
		/**
		 * 如果 tip 属性是文本,此常量为 tip 的显示内容的默认背景颜色
		 */
		private static const DEFAULT_BACKGROUND_COLOR:uint=0xffffff;
		
		/**
		 * 如果 tip 属性是纯 Object 指定的,此常量表示 tip 的显示内容的属性名
		 */
		private static const TEXT_PROPERTY_NAME:String="text";
		
		/**
		 * 如果 tip 属性是纯 Object 指定的,此常量表示 tip 的显示内容的格式的属性名(指定此属性将忽略 css 属性)
		 */
		private static const TEXT_FORMAT_PROPERTY_NAME:String="textFormat";
		
		/**
		 * 如果 tip 属性是纯 Object 指定的,此常量表示 tip 的显示内容的CSS样式的属性名
		 */
		private static const CSS_PROPERTY_NAME:String="css";
		
		/**
		 * 如果 tip 属性是纯 Object 指定的,此常量表示 tip 的显示内容的是否显示背景的属性名
		 */
		private static const BACKGROUND_PROPERTY_NAME:String="background";
		
		/**
		 * 如果 tip 属性是纯 Object 指定的,此常量表示 tip 的显示内容的背景色的属性名
		 */
		private static const BACKGROUND_COLOR_PROPERTY_NAME:String="backgroundColor";
		
		/**
		 * 显示tip对象
		 * @param tipContent 要显示的tip内容对象,可以指定以下对象
		 * <table>
		 * 	<tr>
		 * 		<th>类型</th>
		 * 		<th>说明</th>
		 * 	</tr>
		 * 	<tr>
		 * 		<td>DisplayObject</td>
		 * 		<td>自定义 tip 显示对象</td>
		 * 	</tr>
		 * 	<tr>
		 * 		<td>String</td>
		 * 		<td>纯文本tip,背景为默认颜色 0xffffff , 字体格式为系统中的默认字体格式</td>
		 * 	</tr>
		 * 	<tr>
		 * 		<td>Array</td>
		 * 		<td>
		 * 			第一个元素的类型须是 String 类型,则各元素的表示如下:<br/>
		 * 			<table>
		 * 				<tr>
		 * 					<th>元素编号</th><th>说明</th>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>0</td><td>String,纯文本tip</td>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>1</td><td>TextFormat/StyleSheet/String,CSS样式表,可选,默认为 null</td>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>2</td><td>Boolean/String,是否显示背景,空字符串(null,"")将被转换为 false ,可选,默认为 true</td>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>3</td><td>uint/String ,背景色,十六进制颜色值的字符串须以 0x 开头,可选,默认为 oxffffff</td>
		 * 				</tr>
		 * 			</table>
		 * 		</td>
		 * 	</tr>
		 * 	<tr>
		 * 		<td>Vector.&lt;String&gt;</td>
		 * 		<td>各元素的说明基本同上(Array)</td>
		 * 	</tr>
		 * 	<tr>
		 * 		<td>Object</td>
		 * 		<td>
		 * 			任意对象都可以,但须具备以下属性
		 * 			<table>
		 * 				<tr>
		 * 					<th>属性名</th>
		 * 					<th>说明</th>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>text</td>
		 * 					<td>String,纯文本tip</td>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>textFormat</td>
		 * 					<td>TextFormat,字体格式</td>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>css</td>
		 * 					<td>String,CSS样式表,可选,默认为 null</td>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>background</td>
		 * 					<td>Boolean,是否显示背景,可选,默认为 true</td>
		 * 				</tr>
		 * 				<tr>
		 * 					<td>backgroundColor</td>
		 * 					<td>String/uint,背景色,十六进制颜色值的字符串须以 0x 开头,可选,默认为 oxffffff</td>
		 * 				</tr>
		 * 			</table>
		 * 		</td>
		 * 	</tr>
		 * </table>
		 * @param target tip的附着对象
		 * @param showMillisecond 显示时长(毫秒)
		 * @param showDelayMillisecond 显示延迟(毫秒)
		 * @param hideDelayMillisecond 隐藏延迟(毫秒)
		 * @param showLoc 显示位置,如果不指定此值,则 tipContent 根据鼠标的位置进行显示.指定此值时,静态变量 offset 将被忽略
		 * @param parent tipContent显示的父对象,一般指定为 stage 
		 * 
		 */
		public static function showAny(
			tipContent:*,
			target:InteractiveObject,
			showMillisecond:int=3500,
			showDelayMillisecond:int=400,
			hideDelayMillisecond:int=200,
			showLoc:Point=null,
			parent:DisplayObjectContainer=null
		):void{
			if(tipContent is DisplayObject){
				show(tipContent as DisplayObject,target);
			}else{
				var tipStr:String, textFormat:TextFormat, css:StyleSheet;
				var background:Boolean=DEFAULT_BACKGROUND, backgroundColor:uint=DEFAULT_BACKGROUND_COLOR;
				if(tipContent is String){
					tipStr=tipContent;
				}else if(tipContent is Array){
					if(tipContent[0] is String){
						tipStr=tipContent[0];
						if(tipContent[1] is TextFormat){
							textFormat=tipContent[1];
						}else if(tipContent[1] is StyleSheet){
							css=tipContent[1];
						}else if(tipContent[1] is String){
							css=new StyleSheet();
							css.parseCSS(tipContent[1]);
						}
						if(tipContent.length > 2){
							background=Boolean(tipContent[2]);
						}
						
						if(tipContent.length > 3){
							backgroundColor=uint(tipContent[3]);
						}
					}else{
						return;
					}
				}else if(tipContent is Vector.<String>){
					if(tipContent.length > 0){
						tipStr=tipContent[0];
						if(tipContent.length > 1){
							css=new StyleSheet();
							css.parseCSS(tipContent[1]);
						}
						if(tipContent.length > 2){
							background=Boolean(tipContent[2]);
						}
						
						if(tipContent.length > 3){
							backgroundColor=uint(tipContent[3]);
						}
					}else{
						return;
					}
					
				}else{
					if(tipContent.hasOwnProperty(TEXT_PROPERTY_NAME)){
						tipStr=tipContent[TEXT_PROPERTY_NAME];
						if(tipContent.hasOwnProperty(TEXT_FORMAT_PROPERTY_NAME)){
							textFormat=tipContent[TEXT_FORMAT_PROPERTY_NAME];
						}else if(tipContent.hasOwnProperty(CSS_PROPERTY_NAME)){
							if(tipContent.css is StyleSheet){
								css=tipContent[CSS_PROPERTY_NAME];
							}else if(tipContent[CSS_PROPERTY_NAME] is String){
								css=new StyleSheet();
								css.parseCSS(tipContent[CSS_PROPERTY_NAME]);
							}
						}
						if(tipContent.hasOwnProperty(BACKGROUND_PROPERTY_NAME) && tipContent[BACKGROUND_PROPERTY_NAME] is Boolean){
							background=tipContent[BACKGROUND_PROPERTY_NAME];
						}
						if(tipContent.hasOwnProperty(BACKGROUND_COLOR_PROPERTY_NAME) && tipContent[BACKGROUND_COLOR_PROPERTY_NAME] is uint){
							backgroundColor=tipContent[BACKGROUND_COLOR_PROPERTY_NAME];
						}
					}else{
						return;
					}
				}
				
				txfTip.background=background;
				txfTip.backgroundColor=backgroundColor;
				txfTip.setSelection(0,0);
				
				if(textFormat){
					txfTip.styleSheet=null;
					txfTip.defaultTextFormat=textFormat;
					txfTip.text=tipStr;
				}else if(css){
					//txfTip.defaultTextFormat=null;
					txfTip.styleSheet=css;
					txfTip.htmlText=tipStr;
				}else{
					txfTip.styleSheet=null;
					txfTip.text=tipStr;
				}
				
				txfTip.width=txfTip.textWidth + 4;
				txfTip.height=txfTip.textHeight + 4;
				
				show(txfTip,target);
			}
		}
	}
}